import { isArray, get, isFunction } from "lodash";
import { pathToRegexp } from "path-to-regexp";
import HttpProxy from "http-proxy";
import streamify from "stream-array";

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
const proxy =
  (context: string, options: any) =>
  (ctx: any, next: any): any => {
    let eventRegistered = false;
    const regex = pathToRegexp(context);
    const proxy = HttpProxy.createProxyServer();
    if (!regex.test(ctx.originalUrl)) return next();
    const { events, ...httpProxyOpts } = options;

    ctx.req.token = ctx.cookies.get("token");

    return new Promise((resolve, reject) => {
      if (events && typeof events === "object" && !eventRegistered) {
        Object.entries(events).forEach(([event, handler]) => {
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore
          proxy.on(event, handler);
        });
        eventRegistered = true;
      }

      ctx.res.on("close", () => {
        reject(new Error(`Http response closed while proxying ${ctx.req.url}`));
      });

      ctx.res.on("finish", () => {
        resolve({});
      });
      if (
        get(ctx, 'req.headers["content-type"]', "").includes(
          "multipart/form-data"
        )
      ) {
        httpProxyOpts.buffer = isArray(ctx.req.rawBody)
          ? streamify(ctx.req.rawBody)
          : ctx.req.rawBody;
      }
      if (isFunction(httpProxyOpts.optionsHandle)) {
        httpProxyOpts.optionsHandle(httpProxyOpts, ctx.req);
      }
      proxy.web(ctx.req, ctx.res, httpProxyOpts, (e: any) => {
        console.error(e);
        const status: any = {
          ECONNREFUSED: 503,
          ETIMEOUT: 504,
        };
        const s2: any = status[e.code];
        ctx.status = s2 || 500;
        resolve(ctx);
      });
    });
  };

export default proxy;
